/*
 * Copyright 2023 Expedia, Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.expediagroup.graphql.generator.federation.directives

import com.expediagroup.graphql.generator.annotations.GraphQLDirective
import graphql.introspection.Introspection.DirectiveLocation

/**
 * ```graphql
 * directive @inaccessible on FIELD_DEFINITION
 *     | OBJECT
 *     | INTERFACE
 *     | UNION
 *     | ENUM
 *     | ENUM_VALUE
 *     | SCALAR
 *     | INPUT_OBJECT
 *     | INPUT_FIELD_DEFINITION
 *     | ARGUMENT_DEFINITION
 * ```
 *
 * Inaccessible directive marks location within schema as inaccessible from the GraphQL Gateway. While `@inaccessible` fields are not exposed by the gateway to the clients, they are still available for
 * query plans and can be referenced from `@key` and `@requires` directives. This allows you to not expose sensitive fields to your clients but still make them available for computations. Inaccessible
 * can also be used to incrementally add schema elements (e.g. fields) to multiple subgraphs without breaking composition.
 *
 * > NOTE: Location within schema will be inaccessible from the GraphQL Gateway as long as **any** of the subgraphs marks that location as `@inacessible`.
 *
 * Example:
 *
 * ```kotlin
 * class Product(
 *   val id: String,
 *   @InaccessibleDirective
 *   val secret: String
 * )
 * ```
 *
 * will be generated by the subgraph as
 *
 * ```graphql
 * type Product {
 *   id: String!
 *   secret: String! @inaccessible
 * }
 * ```
 *
 * but will exposed on the GraphQL Gateway as
 *
 * ```graphql
 * type Product {
 *   id: String!
 * }
 * ```
 *
 * @see <a href="https://specs.apollo.dev/inaccessible/v0.2">@inaccessible specification</a>
 */
@LinkedSpec(FEDERATION_SPEC)
@GraphQLDirective(
    name = INACCESSIBLE_DIRECTIVE_NAME,
    description = INACESSIBLE_DIRECTIVE_DESCRIPTION,
    locations = [
        DirectiveLocation.FIELD_DEFINITION,
        DirectiveLocation.OBJECT,
        DirectiveLocation.INTERFACE,
        DirectiveLocation.UNION,
        DirectiveLocation.ENUM,
        DirectiveLocation.ENUM_VALUE,
        DirectiveLocation.SCALAR,
        DirectiveLocation.INPUT_OBJECT,
        DirectiveLocation.INPUT_FIELD_DEFINITION,
        DirectiveLocation.ARGUMENT_DEFINITION
    ]
)
annotation class InaccessibleDirective

internal const val INACCESSIBLE_DIRECTIVE_NAME = "inaccessible"
private const val INACESSIBLE_DIRECTIVE_DESCRIPTION = "Marks location within schema as inaccessible from the GraphQL Gateway"
